﻿#$language = "Python"
#$interface = "1.0"

import os
import sys
import re
from collections import deque

g_local_path = os.path.dirname(os.path.abspath(__file__))
if g_local_path not in sys.path:
    sys.path.insert(0, g_local_path)

from const import *
import debug
CMD_TIMEOUT = 60
CMD_HISTORY = 10

class Prompt():
    def __init__(self, char=None, row=1, style=None):
        self.style = style
        self.char = char
        self.row = row

    def set_prompt(self, obj):
        prompts = {
                    '#': CONST_PROMPT_LINUX_ROOT, 
                    '$': CONST_PROMPT_LINUX_GUEST, 
                    '<': CONST_PROMPT_CRNC
                  }
        obj.Screen.Send('\r')
        obj.Screen.WaitForString(CONST_JUST_WAIT, 1)
        current_row = obj.Screen.CurrentRow
        max_col = obj.Screen.Columns
        get_line = obj.Screen.Get(current_row, 0, current_row, max_col).strip()
        for key in prompts.keys():
            if key == get_line[-1]:
                self.char = prompts[key]
                break
        else:
            if 'sftp' in get_line:
                self.char = CONST_PROMPT_SFTP
            elif get_line[-1] == '>':
                self.char = CONST_PROMPT_CRNC_BOARD
            else:
                err_msg = 'Error prompt "{0}".'.format(get_line)
                obj.Dialog.MessageBox(err_msg, 'Error', 16 | 0)
                return None

        # get prompt span line
        start_line = current_row - 1
        for line in range(start_line, 1, -1):
            get_line = obj.Screen.Get(line, 0, line, max_col)
            if self.char in get_line:
                self.row = current_row - line
                break
        else:
            obj.Dialog.MessageBox('Get prompt row error.', 'Error', 16 | 0)
            return None

        if self.char == CONST_PROMPT_CRNC or \
                self.char == CONST_PROMPT_CRNC_BOARD:
            self.style = CONST_STYLE_CRNC
        elif self.char == CONST_PROMPT_LINUX_ROOT:
            screen = Screen(obj, self)
            rspd = screen.send('ls --color=no /mnt | grep "OMU"\r')
            if 'QFOMU' == rspd:
                self.style = CONST_STYLE_ADA
            elif 'QNOMU' == rspd:
                self.style = CONST_STYLE_MCRNC
            else:
                self.style = CONST_STYLE_LINUX
        elif self.char == CONST_PROMPT_LINUX_GUEST:
            self.style = CONST_STYLE_LINUX
        elif self.char == CONST_PROMPT_SFTP:
            self.style = CONST_STYLE_SFTP
        return None

# remove terminal color as ESC[33m ESC[1;34m ESC]
def strip_escapes(strings):
    escape_regex = re.compile(r'\x1b[\x5b\x5d][0-9;]*m?')
    return escape_regex.sub('', strings)

def align(strings, tab_equ_space=8):
    char_index = 0
    new_str = []
    for char in strings:
        if char == '\t':
            for i in range(tab_equ_space - (char_index % tab_equ_space)):
                new_str.append(' ')
        else:
            new_str.append(char)
        char_index += 1
    return ''.join(new_str)

class FixLenList(deque):
    def __init__(self, length):
        deque.__init__(self)
        self.max_len = length

    def append(self, date):  
        if len(self) == self.max_len:
            self.popleft()
        deque.append(self, date)
    
    def reset_length(self, length):
        if length < self.max_len and length < len(self):
            for var in range(length, self.max_len):
                self.popleft()
        self.max_len = length
        return None

class Screen():
    def __init__(self, obj, prompt=None, history=CMD_HISTORY):
        self.obj = obj
        self.responds = FixLenList(history)
        if prompt is None or prompt.char is None:
            self.prompt = Prompt()
            self.prompt.set_prompt(obj)
        else:
            self.prompt = prompt

    def __del__(self):
        del self.prompt
        del self.responds

    # this function send command, and return result for command
    # but the result rows cannot bigger than windows max row
    # it means that the vertical scroll bar can not move
    def csend(self, command, timeout=CMD_TIMEOUT, prompt=None):
        if prompt is None:
            prompt = self.prompt

        self.obj.Screen.Clear()
        self.obj.Screen.Send(command)
        obj.Screen.WaitForString(prompt.char, timeout)
        current_row = self.obj.Screen.CurrentRow
        if current_row == prompt.row + 1:
            rspd = ''
        else:
            max_col = self.obj.Screen.Columns
            end_row = current_row - prompt.row + 1
            get_lines = []
            for line in range(2, end_row):
                get_lines.append(
                    self.obj.Screen.Get(line, 0, line, max_col).strip()
                )
            rspd = align(("\r".join(get_lines)).strip())
        self.responds.append(rspd)
        return rspd

    def send(self, command, timeout=CMD_TIMEOUT, prompt=None):
        if prompt is None:
            prompt = self.prompt

        self.obj.Screen.Send(command)

        get_lines = self.obj.Screen.ReadString(prompt.char, timeout)
        match_index = self.obj.Screen.MatchIndex
        get_lines = strip_escapes(get_lines)
        lines = deque()
        lines.extend(get_lines.splitlines())
        if match_index != 0:
            for i in range(prompt.row):  # remove prompt lines
                if len(lines) > 0:
                    lines.pop()
        if len(lines) > 0:
            lines.popleft()  # remove command line
        rspd = align(("\r".join(lines)).strip())
        self.responds.append(rspd)
        return rspd
        
    def get_respond(self, num=-1):
        return self.responds[num]
